package program.services;

import program.domain.PCB;
import program.utils.FileUtil;
import java.util.ArrayList;
import java.util.Collections;

/**
 * The type Dist scheduling.
 *
 * @program: OSAlgorithms
 * @description: FCFS磁盘调度
 * @author: Echo -dev
 * @create: 2021 -11-23 15:49
 */
public class DistScheduling {

    /**
     * 时刻
     */
    private int time;

    /**
     * 当前磁道号
     */
    private int curTrack = 53;

    /**
     * 磁道移动总距离
     */
    private int sumTrack;

    /**
     * 等待进程队列
     */
    private ArrayList<PCB> waitQueue = new ArrayList<>();

    private void loadData(String fileName) {
        FileUtil.readFile(fileName);
        String[] data = FileUtil.data;
        for (int i = 0; i < data.length; i++) {
            //分割字符串 0-PID，1-到达时刻，2-磁道号 3-读写时间
            String[] str = data[i].split(",");
            String pid = str[0];
            int arriveTime = Integer.valueOf(str[1]);
            int track = Integer.valueOf(str[2]);
            int rwTime = Integer.valueOf(str[3]);
            PCB pcb = new PCB(pid, arriveTime, track, rwTime);
            waitQueue.add(pcb);
        }
    }

    /**
     * Fcfs scheduling.
     */
    public void FCFSScheduling() {
        loadData("distProcess.txt");
        Collections.sort(waitQueue);
        while (!waitQueue.isEmpty()) {
            PCB p = waitQueue.get(0);
            if (p.getArriveTime() <= time) {
                //进行调度
                System.out.println("时刻:" + time + "," + "进程" + p.getPid() + "访问磁盘," + "磁道" + curTrack + "->" + p.getTrack() + ",读写时间:" + p.getRwTime());
                sumTrack += Math.abs(p.getTrack() - curTrack);
                curTrack = p.getTrack();
                time += p.getRwTime();
                try {
                    Thread.sleep(100 * p.getRwTime());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                waitQueue.remove(0);
            }
            else {
                time++;
            }
        }
        System.out.println("FCFS磁盘调度完成，磁道移动总距离:" + sumTrack);
    }

    /**
     * Sstf scheduling.
     */
    public void SSTFScheduling() {
        loadData("distProcess.txt");
        while (!waitQueue.isEmpty()) {
            boolean tag = false;
            ArrayList<PCB> curQueue = new ArrayList<>();

            while (!waitQueue.isEmpty()&&(waitQueue.get(0).getArriveTime() <= time)) {
                curQueue.add(waitQueue.remove(0));
            }

            //根据距离排序
            if (curQueue.size()>1){
                for (int i=0;i<curQueue.size();i++){
                    for (int j=0;j<curQueue.size() - i -1;j++){
                        if (Math.abs(curQueue.get(j).getTrack()-curTrack)>Math.abs(curQueue.get(j+1).getTrack()-curTrack)){
                            PCB tmp = curQueue.get(j);
                            curQueue.set(j,curQueue.get(j+1));
                            curQueue.set(j+1,tmp);
                        }
                    }
                }
            }

            while (!curQueue.isEmpty()) {
                tag = true;
                PCB p = curQueue.get(0);
                //进行调度
                System.out.println("时刻:" + time + "," + "进程" + p.getPid() + "访问磁盘," + "磁道" + curTrack + "->" + p.getTrack() + ",读写时间:" + p.getRwTime());
                sumTrack += Math.abs(p.getTrack() - curTrack);
                curTrack = p.getTrack();
                time += p.getRwTime();
                try {
                    Thread.sleep(100 * p.getRwTime());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                curQueue.remove(0);
            }
            if (!tag) {
                time++;
            }
        }
        System.out.println("FCFS磁盘调度完成，磁道移动总距离:" + sumTrack);
    }

    /**
     * Scan scheduling.
     */
    public void ScanScheduling(){
        loadData("distProcess.txt");
        while (!waitQueue.isEmpty()) {
            boolean tag = false;
            ArrayList<PCB> curQueue = new ArrayList<>();

            while (!waitQueue.isEmpty()&&(waitQueue.get(0).getArriveTime() <= time)) {
                curQueue.add(waitQueue.remove(0));
            }


            if (curQueue.size()>1){
                //根据磁道排序
                for (int i=0;i<curQueue.size();i++){
                    for (int j=0;j<curQueue.size() - i -1;j++){
                        if (curQueue.get(j).getTrack()<curQueue.get(j+1).getTrack()){
                            PCB tmp = curQueue.get(j);
                            curQueue.set(j,curQueue.get(j+1));
                            curQueue.set(j+1,tmp);
                        }
                    }
                }

                ArrayList<PCB> lowQueue = new ArrayList<>();
                ArrayList<PCB> highQueue = new ArrayList<>();
                for (PCB pcb : curQueue){
                    if (pcb.getTrack()<=curTrack){
                        lowQueue.add(pcb);
                    }else{
                        highQueue.add(pcb);
                    }
                }

                for (int i=0;i<lowQueue.size();i++){
                    for (int j=0;j<lowQueue.size() - i -1;j++){
                        if (Math.abs(lowQueue.get(j).getTrack()-curTrack)>Math.abs(lowQueue.get(j+1).getTrack()-curTrack)){
                            PCB tmp = lowQueue.get(j);
                            lowQueue.set(j,lowQueue.get(j+1));
                            lowQueue.set(j+1,tmp);
                        }
                    }
                }

                for (int i=0;i<highQueue.size();i++){
                    for (int j=0;j<highQueue.size() - i -1;j++){
                        if (Math.abs(highQueue.get(j).getTrack()-curTrack)>Math.abs(highQueue.get(j+1).getTrack()-curTrack)){
                            PCB tmp = highQueue.get(j);
                            highQueue.set(j,highQueue.get(j+1));
                            highQueue.set(j+1,tmp);
                        }
                    }
                }

                curQueue = lowQueue;
                curQueue.addAll(highQueue);

            }

            while (!curQueue.isEmpty()) {
                tag = true;
                PCB p = curQueue.get(0);
                //进行调度
                System.out.println("时刻:" + time + "," + "进程" + p.getPid() + "访问磁盘," + "磁道" + curTrack + "->" + p.getTrack() + ",读写时间:" + p.getRwTime());
                sumTrack += Math.abs(p.getTrack() - curTrack);
                curTrack = p.getTrack();
                time += p.getRwTime();
                try {
                    Thread.sleep(100 * p.getRwTime());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                curQueue.remove(0);
            }
            if (!tag) {
                time++;
            }
        }
        System.out.println("FCFS磁盘调度完成，磁道移动总距离:" + sumTrack);
    }

}
